home *** CD-ROM | disk | FTP | other *** search
/ PC Advisor 2011 May / PC Advisor 190 E.iso / pc / ESSENTIALS / VLC Media Player 1.1 / vlc-1.1.5-win32.exe / lua / intf / http.lua < prev    next >
Encoding:
Text File  |  2010-11-13  |  9.8 KB  |  321 lines

  1. --[==========================================================================[
  2.  http.lua: HTTP interface module for VLC
  3. --[==========================================================================[
  4.  Copyright (C) 2007-2009 the VideoLAN team
  5.  $Id$
  6.  
  7.  Authors: Antoine Cellerier <dionoea at videolan dot org>
  8.  
  9.  This program is free software; you can redistribute it and/or modify
  10.  it under the terms of the GNU General Public License as published by
  11.  the Free Software Foundation; either version 2 of the License, or
  12.  (at your option) any later version.
  13.  
  14.  This program is distributed in the hope that it will be useful,
  15.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  GNU General Public License for more details.
  18.  
  19.  You should have received a copy of the GNU General Public License
  20.  along with this program; if not, write to the Free Software
  21.  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22. --]==========================================================================]
  23.  
  24. --[==========================================================================[
  25. Configuration options:
  26.  * host: A host to listen on.
  27.  * dir: Directory to use as the http interface's root.
  28.  * no_error_detail: If set, do not print the Lua error message when generating
  29.                     a page fails.
  30.  * no_index: If set, don't build directory indexes
  31. --]==========================================================================]
  32.  
  33.  
  34. require "common"
  35.  
  36. vlc.msg.info("Lua HTTP interface")
  37.  
  38. open_tag = "<?vlc"
  39. close_tag = "?>"
  40.  
  41. -- TODO: use internal VLC mime lookup function for mimes not included here
  42. local mimes = {
  43.     txt = "text/plain",
  44.     html = "text/html",
  45.     xml = "text/xml",
  46.     js = "text/javascript",
  47.     css = "text/css",
  48.     png = "image/png",
  49.     jpg = "image/jpeg",
  50.     jpeg = "image/jpeg",
  51.     ico = "image/x-icon",
  52. }
  53.  
  54. function escape(s)
  55.     return (string.gsub(s,"([%^%$%%%.%[%]%*%+%-%?])","%%%1"))
  56. end
  57.  
  58. function process_raw(filename)
  59.     local input = io.open(filename):read("*a")
  60.     -- find the longest [===[ or ]=====] type sequence and make sure that
  61.     -- we use one that's longer.
  62.     local str="X"
  63.     for str2 in string.gmatch(input,"[%[%]]=*[%[%]]") do
  64.         if #str < #str2 then str = str2 end
  65.     end
  66.     str=string.rep("=",#str-1)
  67.  
  68.     --[[┬áFIXME:
  69.     <?xml version="1.0" encoding="charset" standalone="yes" ?> is still a problem. The closing '?>' needs to be printed using '?<?vlc print ">" ?>' to prevent a parse error.
  70.     --]]
  71.     local code0 = string.gsub(input,escape(close_tag)," print(["..str.."[")
  72.     local code1 = string.gsub(code0,escape(open_tag),"]"..str.."]) ")
  73.     local code = "print(["..str.."["..code1.."]"..str.."])"
  74.     --[[ Uncomment to debug
  75.     if string.match(filename,"vlm_cmd.xml$") then
  76.     io.write(code)
  77.     io.write("\n")
  78.     end
  79.     --]]
  80.     return assert(loadstring(code,filename))
  81. end
  82.  
  83. function process(filename)
  84.     local mtime = 0    -- vlc.net.stat(filename).modification_time
  85.     local func = false -- process_raw(filename)
  86.     return function(...)
  87.         local new_mtime = vlc.net.stat(filename).modification_time
  88.         if new_mtime ~= mtime then
  89.             -- Re-read the file if it changed
  90.             if mtime == 0 then
  91.                 vlc.msg.dbg("Loading `"..filename.."'")
  92.             else
  93.                 vlc.msg.dbg("Reloading `"..filename.."'")
  94.             end
  95.             func = process_raw(filename)
  96.             mtime = new_mtime
  97.         end
  98.         return func(...)
  99.     end
  100. end
  101.  
  102.  
  103. function callback_error(path,url,msg)
  104.     local url = url or "<page unknown>"
  105.     return  [[<html xmlns="http://www.w3.org/1999/xhtml">
  106. <head>
  107. <title>Error loading ]]..url..[[</title>
  108. </head>
  109. <body>
  110. <h1>Error loading ]]..url..[[</h1><pre>]]..(config.no_error_detail and "Remove configuration option `no_error_detail' on the server to get more information." or tostring(msg))..[[</pre>
  111. <p>
  112. <a href="http://www.videolan.org/">VideoLAN</a><br/>
  113. <a href="http://www.lua.org/manual/5.1/">Lua 5.1 Reference Manual</a>
  114. </p>
  115. </body>
  116. </html>]]
  117. end
  118.  
  119. function dirlisting(url,listing,acl_)
  120.     local list = {}
  121.     for _,f in ipairs(listing) do
  122.         if not string.match(f,"^%.") then
  123.             table.insert(list,"<li><a href='"..f.."'>"..f.."</a></li>")
  124.         end
  125.     end
  126.     list = table.concat(list)
  127.     local function callback()
  128.         return [[<html xmlns="http://www.w3.org/1999/xhtml">
  129. <head>
  130. <title>Directory listing ]]..url..[[</title>
  131. </head>
  132. <body>
  133. <h1>Directory listing ]]..url..[[</h1><ul>]]..list..[[</ul>
  134. </body>
  135. </html>]]
  136.     end
  137.     return h:file(url,"text/html",nil,nil,acl_,callback,nil)
  138. end
  139.  
  140. -- FIXME: Experimental art support. Needs some cleaning up.
  141. function callback_art(data, request)
  142.     local art = function(data, request)
  143.         local item = vlc.input.item()
  144.         local metas = item:metas()
  145.         local filename = vlc.strings.decode_uri(string.gsub(metas["artwork_url"],"file://",""))
  146.         local size = vlc.net.stat(filename).size
  147.         local ext = string.match(filename,"%.([^%.]-)$")
  148.         local raw = io.open(filename):read("*a")
  149.         local content = [[Content-Type: ]]..mimes[ext]..[[
  150.  
  151. Content-Length: ]]..size..[[
  152.  
  153.  
  154. ]]..raw..[[
  155.  
  156. ]]
  157.         return content
  158.     end
  159.  
  160.     local ok, content = pcall(art, data, request)
  161.     if not ok then
  162.         return [[Status: 404
  163. Content-Type: text/plain
  164. Content-Length: 5
  165.  
  166. Error
  167. ]]
  168.     end
  169.     return content
  170. end
  171.  
  172. function file(h,path,url,acl_,mime)
  173.     local generate_page = process(path)
  174.     local callback = function(data,request)
  175.         -- FIXME: I'm sure that we could define a real sandbox
  176.         -- redefine print
  177.         local page = {}
  178.         local function pageprint(...)
  179.             for i=1,select("#",...) do
  180.                 if i== 1 then
  181.                     table.insert(page,tostring(select(i,...)))
  182.                 else
  183.                     table.insert(page," "..tostring(select(i,...)))
  184.                 end
  185.             end
  186.         end
  187.         _G._GET = parse_url_request(request)
  188.         local oldprint = print
  189.         print = pageprint
  190.         local ok, msg = pcall(generate_page)
  191.         -- reset
  192.         print = oldprint
  193.         if not ok then
  194.             return callback_error(path,url,msg)
  195.         end
  196.         return table.concat(page)
  197.     end
  198.     return h:file(url or path,mime,nil,nil,acl_,callback,nil)
  199. end
  200.  
  201. function rawfile(h,path,url,acl_)
  202.     local filename = path
  203.     local mtime = 0    -- vlc.net.stat(filename).modification_time
  204.     local page = false -- io.open(filename):read("*a")
  205.     local callback = function(data,request)
  206.         local new_mtime = vlc.net.stat(filename).modification_time
  207.         if mtime ~= new_mtime then
  208.             -- Re-read the file if it changed
  209.             if mtime == 0 then
  210.                 vlc.msg.dbg("Loading `"..filename.."'")
  211.             else
  212.                 vlc.msg.dbg("Reloading `"..filename.."'")
  213.             end
  214.             page = io.open(filename):read("*a")
  215.             mtime = new_mtime
  216.         end
  217.         return page
  218.     end
  219.     return h:file(url or path,nil,nil,nil,acl_,callback,nil)
  220. end
  221.  
  222. function parse_url_request(request)
  223.     if not request then return {} end
  224.     local t = {}
  225.     for k,v in string.gmatch(request,"([^=&]+)=?([^=&]*)") do
  226.         local k_ = vlc.strings.decode_uri(k)
  227.         local v_ = vlc.strings.decode_uri(v)
  228.         if t[k_] ~= nil then
  229.             local t2
  230.             if type(t[k_]) ~= "table" then
  231.                 t2 = {}
  232.                 table.insert(t2,t[k_])
  233.                 t[k_] = t2
  234.             else
  235.                 t2 = t[k_]
  236.             end
  237.             table.insert(t2,v_)
  238.         else
  239.             t[k_] = v_
  240.         end
  241.     end
  242.     return t
  243. end
  244.  
  245. local function find_datadir(name)
  246.     local list = vlc.misc.datadir_list(name)
  247.     for _, l in ipairs(list) do
  248.         local s = vlc.net.stat(l)
  249.         if s then
  250.             return l
  251.         end
  252.     end
  253.     error("Unable to find the `"..name.."' directory.")
  254. end
  255. http_dir = config.dir or find_datadir("http")
  256.  
  257. do
  258.     local oldpath = package.path
  259.     package.path = http_dir.."/?.lua"
  260.     local ok, err = pcall(require,"custom")
  261.     if not ok then
  262.         vlc.msg.warn("Couldn't load "..http_dir.."/custom.lua",err)
  263.     else
  264.         vlc.msg.dbg("Loaded "..http_dir.."/custom.lua")
  265.     end
  266.     package.path = oldpath
  267. end
  268. local files = {}
  269. local function load_dir(dir,root,parent_acl)
  270.     local root = root or "/"
  271.     local has_index = false
  272.     local my_acl = parent_acl
  273.     do
  274.         local af = dir.."/.hosts"
  275.         local s = vlc.net.stat(af)
  276.         if s and s.type == "file" then
  277.             -- We found an acl
  278.             my_acl = vlc.acl(false)
  279.             my_acl:load_file(af)
  280.         end
  281.     end
  282.     local d = vlc.net.opendir(dir)
  283.     for _,f in ipairs(d) do
  284.         if not string.match(f,"^%.") then
  285.             local s = vlc.net.stat(dir.."/"..f)
  286.             if s.type == "file" then
  287.                 local url
  288.                 if f == "index.html" then
  289.                     url = root
  290.                     has_index = true
  291.                 else
  292.                     url = root..f
  293.                 end
  294.                 local ext = string.match(f,"%.([^%.]-)$")
  295.                 local mime = mimes[ext]
  296.                 -- print(url,mime)
  297.                 if mime and string.match(mime,"^text/") then
  298.                     table.insert(files,file(h,dir.."/"..f,url,my_acl,mime))
  299.                 else
  300.                     table.insert(files,rawfile(h,dir.."/"..f,url,my_acl))
  301.                 end
  302.             elseif s.type == "dir" then
  303.                 load_dir(dir.."/"..f,root..f.."/",my_acl)
  304.             end
  305.         end
  306.     end
  307.     if not has_index and not config.no_index then
  308.         -- print("Adding index for", root)
  309.         table.insert(files,dirlisting(root,d,my_acl))
  310.     end
  311.     return my_acl
  312. end
  313.  
  314. local u = vlc.net.url_parse( config.host or "0.0.0.0:8080" )
  315. h = vlc.httpd(u.host,u.port)
  316. local root_acl = load_dir( http_dir )
  317. local a = h:handler("/art",nil,nil,root_acl,callback_art,nil)
  318.  
  319. while not vlc.misc.lock_and_wait() do end -- everything happens in callbacks
  320.  
  321.